package be.jaisy.osgi.transaction;


public class TransactionTemplate {

	private ITransactionManager transactionManager;

	public TransactionTemplate(ITransactionManager transactionManager) {
		super();
		if(transactionManager==null)
			throw new IllegalArgumentException("TransactionManager is mandatory to create TransactionTemplate");
		this.transactionManager = transactionManager;
	}

	public void execute(TransactionCallbackWithoutResult action) throws TransactionException {
		TransactionStatus status = new TransactionStatus();		
		try {
			this.transactionManager.beginTransaction();
			action.doInTransactionWithoutResult(status);
		} catch (RuntimeException ex) {
			// Transactional code threw application exception -> rollback
			rollbackOnException(status, ex);
			throw ex;
		} catch (Error err) {
			// Transactional code threw error -> rollback
			rollbackOnException(status, err);
			throw err;
		}
		this.transactionManager.commitTransaction();
	}
	
	public Object execute(TransactionCallback action) throws TransactionException {
		TransactionStatus status = new TransactionStatus();
		Object result = null;
		try {
			this.transactionManager.beginTransaction();
			result = action.doInTransaction(status);
		} catch (RuntimeException ex) {
			// Transactional code threw application exception -> rollback
			rollbackOnException(status, ex);
			throw ex;
		} catch (Error err) {
			// Transactional code threw error -> rollback
			rollbackOnException(status, err);
			throw err;
		}
		this.transactionManager.commitTransaction();
		return result;
	}

	/**
	 * Perform a rollback, handling rollback exceptions properly.
	 * 
	 * @param status
	 *            object representing the transaction
	 * @param ex
	 *            the thrown application exception or error
	 * @throws TransactionException
	 *             in case of a rollback error
	 */
	private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {
		try {
			this.transactionManager.rollbackTransaction();
		} catch (RuntimeException ex2) {
			throw ex2;
		} catch (Error err) {
			throw err;
		}
	}

}
